/*
 * Service.java
 *
 */

/*
 * TODO:
 * - encodeArg: can identify if the class implement 'Iterable' interface, if so, process! :)
 */

package net.kernub.kebcore.client;

import java.util.ArrayList;
import java.util.Iterator;
import java.lang.Object;
import java.lang.Iterable;

import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.URL;
import com.google.gwt.core.client.JavaScriptObject;

public class Service
{
	public interface Callback<Ty>
	{
		public void onReturn( Ty object );
	};

	private static Service instance = null;
	private static final String url = "backend/rpc.php";
	private static boolean deferredCall = true;

	public Service()
	{
	}

	public static Service inst()
	{
		return Service.instance;
	}

	public static void create()
	{
		if( instance == null )
		{
			instance = new Service();
		}
	}

	public static void setDeferredCall( final boolean b )
	{
		Service.deferredCall = b;
	}

	public static void call( final String path, final Callback cb )
	{
		Service.instance._call( path, null, cb );
	}

	public static void call( final String path, final Object a0, final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0);
		Service.instance._call( path, args, cb );
	}

	public static void call( final String path, final Object a0, final Object a1, final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0) + "&" + Service.encodeArg("a1", a1);
		Service.instance._call( path, args, cb );
	}

	public static void call( final String path, final Object a0, final Object a1, final Object a2, final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0) + "&" + Service.encodeArg("a1", a1) + "&" + Service.encodeArg("a2", a2);
		Service.instance._call( path, args, cb );
	}

	public static void call( final String path, final Object a0, final Object a1, final Object a2, final Object a3, final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0) + "&" + Service.encodeArg("a1", a1) + "&" + Service.encodeArg("a2", a2) + "&" +
									Service.encodeArg("a3", a3);
		Service.instance._call( path, args, cb );
	}

	public static void call( final String path, final Object a0, final Object a1, final Object a2, final Object a3, final Object a4, final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0) + "&" + Service.encodeArg("a1", a1) + "&" + Service.encodeArg("a2", a2) + "&" +
									Service.encodeArg("a3", a3) + "&" + Service.encodeArg("a4", a4);
		Service.instance._call( path, args, cb );
	}

	public static void call( final String path, final Object a0, final Object a1, final Object a2, final Object a3, final Object a4, final Object a5, 
													 final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0) + "&" + Service.encodeArg("a1", a1) + "&" + Service.encodeArg("a2", a2) + "&" +
									Service.encodeArg("a3", a3) + "&" + Service.encodeArg("a4", a4) + "&" + Service.encodeArg("a5", a5);
		Service.instance._call( path, args, cb );
	}

	public static void call( final String path, final Object a0, final Object a1, final Object a2, final Object a3, final Object a4, final Object a5, 
													 final Object a6, final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0) + "&" + Service.encodeArg("a1", a1) + "&" + Service.encodeArg("a2", a2) + "&" +
									Service.encodeArg("a3", a3) + "&" + Service.encodeArg("a4", a4) + "&" + Service.encodeArg("a5", a5) + "&" +
									Service.encodeArg("a6", a6);
		Service.instance._call( path, args, cb );
	}

	public static void call( final String path, final Object a0, final Object a1, final Object a2, final Object a3, final Object a4, final Object a5, 
													 final Object a6, final Object a7, final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0) + "&" + Service.encodeArg("a1", a1) + "&" + Service.encodeArg("a2", a2) + "&" +
									Service.encodeArg("a3", a3) + "&" + Service.encodeArg("a4", a4) + "&" + Service.encodeArg("a5", a5) + "&" +
									Service.encodeArg("a6", a6) + "&" + Service.encodeArg("a7", a7);
		Service.instance._call( path, args, cb );
	}

	public static void call( final String path, final Object a0, final Object a1, final Object a2, final Object a3, final Object a4, final Object a5, 
													 final Object a6, final Object a7, final Object a8, final Callback cb )
	{
		final String args = Service.encodeArg("a0", a0) + "&" + Service.encodeArg("a1", a1) + "&" + Service.encodeArg("a2", a2) + "&" +
									Service.encodeArg("a3", a3) + "&" + Service.encodeArg("a4", a4) + "&" + Service.encodeArg("a5", a5) + "&" +
									Service.encodeArg("a6", a6) + "&" + Service.encodeArg("a7", a7) + "&" + Service.encodeArg("a8", a8);
		Service.instance._call( path, args, cb );
	}

	private void _call( final String path, final String args, final Callback callback )
	{
		final String localargs = (args=="") ? null : args;

		String url = GWT.getHostPageBaseURL() + Service.url + "?p=" + URL.encode(path);

		final Backend.Callback backcallback = new Backend.Callback() {
			public void onReturn( boolean hasError, JavaScriptObject object )
			{
				if( !hasError && callback != null )
					callback.onReturn( object );
			}
		};

		if( Service.deferredCall )
			Backend.inst().callDeferred( url, localargs, backcallback );
		else
			Backend.inst().call( url, localargs, backcallback );
	}

	// detect argument type and encode it
	public static String encodeArg( final String argName, final Object a )
	{	
		// TODO: can identify if the class implement 'Iterable' interface, if so, process! :)
		/*
		Class<Object> listIf = a.getClass().getInterfaces();
		for( Class c : listIf )
		{
			if( c == Iterable.class )
				GWT.log( "encodeArg: argName: " + argName + " is iterable!!!!! YOUPI!", null );
		}
		*/

		String r = "";

		if( a.getClass() == ArrayList.class )
		{
			final ArrayList<Object> arr = (ArrayList<Object>) a;

			// empty, create argument anyway -> no!!! this is creating an pseudo-empty-array on server side!
			if( arr.size() == 0 )
			{
				//r = argName + "[]=";
				return r;
			}

			int count = arr.size();
			for( Iterator<Object> it = arr.iterator(); it.hasNext(); )
			{
				r += argName + "[]=" + URL.encode( it.next().toString() );
				count--;
				if( count > 0 )
					r += "&";
			}

			return r;
		}

		r = argName + "=" + URL.encode( a.toString() );
		return r;
	}
};

